package com.ctu.autodial.util;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.SystemClock;
import android.util.Log;

import com.ctu.app.utils.ConfigureLog4J;
//import com.ctu.app.utils.LogUtil;
import com.uraroji.garage.android.lame.SimpleLame;

import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import org.apache.log4j.Logger;

/**
 * Created by kaiz on 14-3-10.
 */
public class CallRecord {
	AudioRecord recorder;
	int bufferSize;
	short[] buffer;
	byte[] mp3buffer;
	SimpleDateFormat format = new SimpleDateFormat("yy年MM月dd日kk点mm分ss");
	String fileName;
	boolean isRecording = true;
	boolean isSaving = true;
	FileOutputStream mp3Writer = null;
	RechargeResultListener rechargeResultListener;
	boolean isCheckResult = false;
	long now;
	long stageStartTime;
	long temp;
	final double threshold = 20.54;// 阈值勿动！！！
	final double volumeGainLevel = 19.77;
	final int sampleRate = 8000;
	double blockLength = 72;// 采样块时间长度，勿动
	double clipA = 0;
	double clipB = 0;
	double clipC = 0;
	int soundClip = 0;
	double clipAVolumeSum = 0;
	double volumeGain = 1.0;
	int soundBlockCount = 0;
	private static final String EXCEPTION_FILE_NAME = "AutoDialRunException";
	private static Logger runLogger;

	public enum CallResult {
		SUCCESS, INVALID_PWD, WRONG_PWD, INVALID_PHONE, ERROR,
	};

	String[] successList = { "13年01月01日08点22分16_13623117402.raw",
			"13年01月01日08点35分34_18778381651.raw",
			"13年01月01日08点56分30_13588401263.raw",
			"13年01月01日10点55分32_18225278901.raw",
			"13年01月01日11点11分39_18294990524.raw",
			"14年03月13日14点27分23_15222217194.raw",
			"14年03月13日14点43分57_14797017053.raw",
			"14年03月13日15点15分20_13549012361.raw",
			"14年03月13日15点28分17_13840259470.raw",
			"14年03月13日15点45分10_15125715113.raw",
			"14年03月13日16点00分20_15909493752.raw",
			"14年03月13日16点25分02_15246026367.raw",
			"14年03月13日17点03分21_18392568044.raw",
			"14年03月13日17点20分25_18709604461.raw",
			"14年03月13日17点58分27_18889545207.raw",
			"14年03月13日18点12分45_15261420804.raw" };

	String[] invalidList = { "13年01月01日08点09分30_15811157123.raw",
			"13年01月01日08点13分08_15811157123.raw",
			"13年01月01日08点24分23_13623117402.raw",
			"13年01月01日08点26分13_13623117402.raw",
			"13年01月01日08点28分26_13623117402.raw",
			"13年01月01日08点36分52_18778381651.raw",
			"13年01月01日08点38分15_18778381651.raw",
			"13年01月01日08点39分33_18778381651.raw",
			"13年01月01日08点58分11_13588401263.raw",
			"13年01月01日08点59分37_13588401263.raw",
			"13年01月01日09点07分34_13588401263.raw",
			"13年01月01日10点56分57_18225278901.raw",
			"13年01月01日10点58分25_18225278901.raw",
			"13年01月01日10点59分48_18225278901.raw",
			"13年01月01日11点18分49_18294990524.raw",
			"13年01月01日11点20分52_18294990524.raw",
			"14年03月13日14点32分25_15222217194.raw",
			"14年03月13日14点34分24_15222217194.raw",
			"14年03月13日14点45分18_14797017053.raw",
			"14年03月13日14点48分06_14797017053.raw",
			"14年03月13日15点16分57_13549012361.raw",
			"14年03月13日15点18分21_13549012361.raw",
			"14年03月13日15点19分48_13549012361.raw",
			"14年03月13日15点29分35_13840259470.raw",
			"14年03月13日15点31分25_13840259470.raw",
			"14年03月13日15点32分48_13840259470.raw",
			"14年03月13日15点46分30_15125715113.raw",
			"14年03月13日15点47分49_15125715113.raw",
			"14年03月13日16点01分37_15909493752.raw",
			"14年03月13日16点02分55_15909493752.raw",
			"14年03月13日16点26分22_15246026367.raw",
			"14年03月13日16点27分41_15246026367.raw",
			"14年03月13日16点53分44_15212452057.raw",
			"14年03月13日16点55分03_15212452057.raw",
			"14年03月13日17点04分39_18392568044.raw",
			"14年03月13日17点07分17_18392568044.raw",
			"14年03月13日17点21分43_18709604461.raw",
			"14年03月13日17点23分15_18709604461.raw",
			"14年03月13日17点51分20_15899193842.raw",
			"14年03月13日17点59分52_18889545207.raw",
			"14年03月13日18点01分13_18889545207.raw",
			"14年03月13日18点02分42_18889545207.raw",
			"14年03月13日18点14分04_15261420804.raw",
			"14年03月13日18点15分34_15261420804.raw",
			"14年03月13日18点18分32_15261420804.raw" };

	String[] wrongList = { "13年01月01日08点15分32_15811157123.raw",
			"13年01月01日08点16分59_15811157123.raw",
			"13年01月01日08点19分34_15811157123.raw",
			"13年01月01日08点29分40_13623117402.raw",
			"13年01月01日08点30分58_13623117402.raw",
			"13年01月01日08点32分20_13623117402.raw",
			"13年01月01日08点40分58_18778381651.raw",
			"13年01月01日08点42分36_18778381651.raw",
			"13年01月01日08点43分54_18778381651.raw",
			"13年01月01日09点09分25_13588401263.raw",
			"13年01月01日09点10分45_13588401263.raw",
			"13年01月01日09点12分05_13588401263.raw",
			"13年01月01日11点04分23_18225278901.raw",
			"13年01月01日11点05分49_18225278901.raw",
			"14年03月13日14点21分29_18294990524.raw",
			"14年03月13日14点24分21_18294990524.raw",
			"14年03月13日14点37分41_15222217194.raw",
			"14年03月13日14点40分18_15222217194.raw",
			"14年03月13日14点50分03_14797017053.raw",
			"14年03月13日15点11分04_14797017053.raw",
			"14年03月13日15点12分29_14797017053.raw",
			"14年03月13日15点21分31_13549012361.raw",
			"14年03月13日15点22分54_13549012361.raw",
			"14年03月13日15点24分22_13549012361.raw",
			"14年03月13日15点35分43_13840259470.raw",
			"14年03月13日15点37分16_13840259470.raw",
			"14年03月13日15点38分39_13840259470.raw",
			"14年03月13日15点53分06_15125715113.raw",
			"14年03月13日15点57分28_15125715113.raw",
			"14年03月13日16点20分17_15909493752.raw",
			"14年03月13日16点21分35_15909493752.raw",
			"14年03月13日16点22分54_15909493752.raw",
			"14年03月13日16点59分18_15212452057.raw",
			"14年03月13日17点00分39_15212452057.raw",
			"14年03月13日17点08分54_18392568044.raw",
			"14年03月13日17点14分57_18392568044.raw",
			"14年03月13日17点16分29_18392568044.raw",
			"14年03月13日17点52分39_15899193842.raw",
			"14年03月13日17点54分03_15899193842.raw",
			"14年03月13日17点55分29_15899193842.raw",
			"14年03月13日18点07分40_18889545207.raw",
			"14年03月13日18点08分58_18889545207.raw",
			"14年03月13日18点10分21_18889545207.raw",
			"14年03月13日18点19分57_15261420804.raw",
			"14年03月13日18点21分51_15261420804.raw",
			"14年03月13日18点23分21_15261420804.raw" };

	public CallRecord(RechargeResultListener resultListener) {
		runLogger = ConfigureLog4J.configure();
		rechargeResultListener = resultListener;
		SimpleLame.init(sampleRate, 1, sampleRate, 32);
	}

	/**
	 * 每天录音保存到一个文件夹 14:49 待添加
	 */
	private void createRecordDir() {

	}

	public void StartRecord(String phone) throws IllegalStateException {
		isCheckResult = false;
		isRecording = true;
		isSaving = true;
		soundClip = 0;
		clipA = 0;
		clipB = 0;
		clipC = 0;
		fileName = "/sdcard/autodial/" + format.format(new Date()) + "_"
				+ phone + ".mp3";
		clipAVolumeSum = 0;
		volumeGain = 1.0;

		Thread recordThread = new Thread(new Runnable() {
			@Override
			public void run() {
				android.os.Process
						.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);

				if (recorder == null) {
					bufferSize = AudioRecord.getMinBufferSize(sampleRate,
							AudioFormat.CHANNEL_IN_MONO,
							AudioFormat.ENCODING_PCM_16BIT);
					recorder = new AudioRecord(
							MediaRecorder.AudioSource.VOICE_DOWNLINK,
							sampleRate, AudioFormat.CHANNEL_IN_MONO,
							AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);

					if (recorder == null) {// 排除问题
						recorder = new AudioRecord(
								MediaRecorder.AudioSource.VOICE_DOWNLINK,
								sampleRate, AudioFormat.CHANNEL_IN_MONO,
								AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
					}

					buffer = new short[bufferSize];
					mp3buffer = new byte[(int) (7200 + buffer.length * 2 * 1.25)];
				}

				try {
					mp3Writer = new FileOutputStream(new File(fileName));
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
					runLogger.error("NO FOUND RECORD FILE...", e1);
					// LogUtil.saveExceptionLog2File(e1, EXCEPTION_FILE_NAME);
				}

				recorder.startRecording();// 开启录音

				long startTime = SystemClock.elapsedRealtime();
				long nowTime = 0;

				int soundBlockCount = 0;
				while (isRecording) {
					Arrays.fill(buffer, (byte) 0);
					try {
						soundBlockCount++;
						int readSize = recorder.read(buffer, 0, bufferSize);
						now = soundBlockCount;
						// 保存录音
						int encResult = SimpleLame.encode(buffer, buffer,
								readSize, mp3buffer);
						if (encResult != 0) {
							mp3Writer.write(mp3buffer, 0, encResult);
						} else {
							Log.e("kaiz", "mp3Writer encode error: "
									+ encResult);
						}
						// 检查结果
						if (isCheckResult) {
							// 获取音量
							double v = calculateVolume(buffer);

							if (nowTime < startTime) {
								nowTime = SystemClock.elapsedRealtime();
								blockLength = (nowTime - startTime)
										/ soundBlockCount;
							}
							/*
							 * if (stageStartTime+50 < now ) { Log.d("kaiz",
							 * now+" wav volume: " + v); stageStartTime = now; }
							 */

							if (stageStartTime == 0) {
								if (v > threshold) {
									if (temp == 0) {
										temp = now;
									} else if (temp + 2 <= now) {
										stageStartTime = temp;
										temp = 0;
										clipAVolumeSum = 0;
									}
									clipAVolumeSum += v;
								} else {
									if (temp + 2 < now) {
										temp = 0;
										clipAVolumeSum = 0;
									}
								}
							} else {
								if (v <= threshold) {
									if (temp == 0) {
										temp = now;
									} else if (temp + 2 <= now) {
										// System.out.println("start: "+df.format(stageStartTime*0.072)+" talk length "
										// + df.format(((float)(temp -
										// stageStartTime))*0.072));
										if (soundClip == 0) {
											clipA = (temp - stageStartTime)
													* blockLength;
											double tempVolume = clipAVolumeSum
													/ (temp - stageStartTime);
											if (tempVolume < volumeGainLevel)
												volumeGain = 1 + ((volumeGainLevel - tempVolume) / tempVolume);
										} else if (soundClip == 1) {
											clipB = (temp - stageStartTime)
													* blockLength;
										} else if (soundClip == 2) {
											clipC = (temp - stageStartTime)
													* blockLength;
										}
										soundClip++;
										stageStartTime = 0;
										temp = 0;
										clipAVolumeSum = 0;
									}
								} else {
									temp = 0;
									clipAVolumeSum += v;
								}
							}

						}
					} catch (Throwable e) {
						e.printStackTrace();
						break;
					}
				}
				try {
					if (soundClip == 2 && clipC < 0.1) {
						clipC = (temp - stageStartTime) * blockLength;
					}
					if (recorder != null) {
						recorder.stop();
						recorder.release();
						recorder = null;
					}
				} catch (Throwable e) {
					e.printStackTrace();
					runLogger.error("fail to get record resource...", e);

					// LogUtil.saveExceptionLog2File(e, EXCEPTION_FILE_NAME);
					recorder = null;
				}

				try {
					int flushResult = SimpleLame.flush(mp3buffer);
					if (flushResult > 0) {
						mp3Writer.write(mp3buffer, 0, flushResult);
					} else {
						Log.e("kaiz", "mp3Writer flush error: " + flushResult);
					}
					mp3Writer.close();
					mp3Writer = null;
				} catch (IOException e) {
					e.printStackTrace();
					runLogger.error("mp3Writer...", e);
					// LogUtil.saveExceptionLog2File(e, EXCEPTION_FILE_NAME);

				}

				if (!isSaving) {
					File file = new File(fileName);

					if (file.exists()) {
						file.delete();
						Log.d("kaiz", "delete file: " + fileName);
					}
				}
			}
		});
		recordThread.start();
	}

	public void SaveRecord() {
		isRecording = false;
		isSaving = true;
		// recorder.stop();
		// recorder.release();
		// recorder = null;

	}

	public void CancelRecord() {
		isRecording = false;
		isSaving = false;
		// if (recorder != null) {
		// recorder.stop();
		// recorder.release();
		// recorder = null;
		// }

	}

	public CallResult GetResult() {
		Log.d("kaiz", "clipA: " + clipA + " clipB: " + clipB + " clipC: "
				+ clipC);
		if (clipB > 839 && clipB < 1139 && clipC > 1007 && clipC < 1307)
			return CallResult.SUCCESS;
		if (clipB > 318 && clipB < 618 && clipC > 1403 && clipC < 1803)
			return CallResult.INVALID_PWD;
		if (clipB > 318 && clipB < 618 && clipC > 1892 && clipC < 2192)
			return CallResult.WRONG_PWD;
		if (clipB > 318 && clipB < 618 && clipC > 642 && clipC < 942)
			return CallResult.INVALID_PHONE;
		return CallResult.ERROR;
	}

	private double calculateVolume(short[] clipBuffer) {
		double sumVolume = 0.0;
		double avgVolume = 0.0;
		double volume = 0.0;
		for (int i = 0; i < clipBuffer.length; i++) {
			// int v1 = buffer[i] & 0xFF;
			// int v2 = buffer[i + 1] & 0xFF;
			// int temp = v1 + (v2 << 8);// 小端
			// if (temp >= 0x8000) {
			// temp = 0xffff - temp;
			// }
			// sumVolume += Math.abs(temp);
			sumVolume += clipBuffer[i] * clipBuffer[i];
		}
		avgVolume = Math.sqrt(sumVolume / clipBuffer.length);
		volume = Math.log10(1 + avgVolume) * 10 * volumeGain;
		return volume;
	}

	/*
	 * int clipLength = 60; void StartTest() { Thread testThread = new
	 * Thread(new Runnable() {
	 * 
	 * @Override public void run() { //short[] clipBuffer = new
	 * short[clipLength]; for (int i=0; i<successList.length; i++) {
	 * 
	 * readBlockCount = 0; long readTime = 0; try { ObjectInputStream rawReader
	 * = new ObjectInputStream(new FileInputStream(new File(fileName))); int
	 * blockLength = rawReader.readInt(); Log.d("kaiz",
	 * "read block length: "+blockLength); long time = 0; short[] readBuffer =
	 * null; short[] preBuffer = null; while (true) { time =
	 * rawReader.readLong(); readBuffer = null; readBuffer =
	 * (short[])rawReader.readObject(); if (readBuffer.equals(preBuffer)) {
	 * preBuffer = null; } preBuffer = readBuffer.clone(); if (time > readTime)
	 * readTime = time; readBlockCount++; if (time >= 45000) { double v =
	 * calculateVolume(readBuffer); Log.d("kaiz", readBlockCount+" wav volume: "
	 * + v);
	 * 
	 * 
	 * } //Log.d("kaiz",
	 * "read time: "+time+"; read buffer length: "+readBuffer.length); } } catch
	 * (EOFException e) { Log.d("kaiz",
	 * fileName+" read end; time: "+readTime+"; block count: "+readBlockCount);
	 * } catch (Throwable e) { e.printStackTrace(); } }
	 * 
	 * } }); testThread.start(); }
	 */

	public void CheckResult() {
		isCheckResult = true;
	}

	public static interface RechargeResultListener {
		public void Result();
	}
}
